#include "nr_scheduler_manager.h"

nr_scheduler_manager::nr_scheduler_manager(nr_device_item_manager& item_manager,
    nr_channel_manager& channel_manager, nr_io_manager& io_manager)
    : m_item_manager(item_manager)
    , m_channel_manager(channel_manager)
    , m_io_manager(io_manager)
    , m_active_scheduler(NULL)
    , m_is_record_on(false)
{
}

nr_scheduler_manager::~nr_scheduler_manager()
{
}

nr_error_t nr_scheduler_manager::load()
{
    // Load the existed schedulers from the database
    // Create a normal scheduler at default
    nr_scheduler *scheduler = new nr_scheduler_normal(false);
    scheduler->name() = "default scheduler";
    m_schedulers.insert(scheduler->name(), scheduler);
    
    // Set the active scheduler and let it run now
    m_active_scheduler = scheduler;

    m_active_scheduler->set_active(true);

    // Start the check timer, check it every second 
    m_scheduler_timer.singleShot(1000, this, SLOT(on_scheduler_timer()));
    
    return NR_ERROR_NONE;
}

nr_error_t nr_scheduler_manager::unload()
{
    // Unload it
    
    return NR_ERROR_NONE;
}

nr_error_t nr_scheduler_manager::add_scheduler(const QString& name, 
    nr_scheduler* scheduler)
{
    // Check whether the name existed
    if (m_schedulers.contains(name))
        return NR_ERROR_NAME_CONFLICTED;

    m_schedulers.insert(name, scheduler);

    return NR_ERROR_NONE;
}

void nr_scheduler_manager::remove_scheduler(const QString& name)
{
    // Try to find it and destroy it 

}

void nr_scheduler_manager::on_scheduler_timer()
{
    // Check the active scheduler
    if (m_active_scheduler != NULL)
    {
        bool scheduler_on = m_active_scheduler->check_scheduler();

        if (scheduler_on) // The record should be on
            record_on();
        else
            record_off();
    }
    
    // Start the check timer again
    m_scheduler_timer.singleShot(1000, this, SLOT(on_scheduler_timer()));
}

nr_error_t nr_scheduler_manager::record_on()
{
    if (m_is_record_on)
        return NR_ERROR_NONE;

    // Start all the device for simple 
    nr_device_item_server& item_server = m_item_manager.root_item();

    // Start the group
    foreach(nr_device_group* group, item_server.groups())
    {
        start_group(group);
    }
    
    // Start the item itself and its child item
    start_item(&item_server);

    // Start each output channel
    foreach(nr_channel_output *output_channel, m_output_channels)
    {
        output_channel->start();
    }

    // Set the record flag to true
    m_is_record_on = true;

    return NR_ERROR_NONE;
}

nr_error_t nr_scheduler_manager::record_off()
{
    if (!m_is_record_on)
        return NR_ERROR_NONE;

    // Stop all the record channel
    foreach(nr_channel_output* output_channel, m_output_channels)
    {
        m_channel_manager.destroy_output_channel(output_channel);
    }
    
    m_output_channels.clear();

    // Set the record flag to true
    m_is_record_on = false;

    return NR_ERROR_NONE;
}

void nr_scheduler_manager::start_item(nr_device_item *item)
{
    if (item == NULL)
        return ;
    
    // Try to start its child item recursively 
    foreach(nr_device_item *sub_item, item->items())
    {
        start_item(sub_item);
    }

    #define NR_DEVICE_TYPE_ID_APMD7XX 200
    
    // We only care the APMD7XX device for easy, only used in the demo
    if (item->device_type()->id() != NR_DEVICE_TYPE_ID_APMD7XX)
        return ;
    
    // Create a output channel for device item
    nr_channel_output *output_channel = NULL;
    nr_error_t status = m_channel_manager.create_output_channel(item->id(), 
        *this, output_channel);

    // Add to the output list 
    if (NR_SUCCEED(status))
    {
        m_output_channels.push_back(output_channel);
    }
}

void nr_scheduler_manager::start_group(nr_device_group *group)
{
    if (group == NULL)
        return ;

    // Start each sub-item
    foreach(nr_device_item* item, group->items())
    {
        start_item(item);
    }
    
    // Start each sub-group
    foreach(nr_device_group* sub_group, group->groups())
    {
        start_group(sub_group);
    }
}

void nr_scheduler_manager::on_data(nr_data *data)
{
    nr_io* io = m_io_manager.io();
    if (io != NULL)
    {
        io->write_data(data);
    }
}

void nr_scheduler_manager::on_event(nr_event *evt)
{
    nr_io* io = m_io_manager.io();
    if (io != NULL)
    {
        io->write_event(evt);
    }
}

